/**
 * 
 */
package com.ditty.router;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import com.ditty.annotation.ActionMapping;
import com.ditty.annotation.ClearAction;
import com.ditty.annotation.ClearActionInterceptor;
import com.ditty.interceptor.AbstractActionIntercptor;
import com.ditty.interceptor.Interceptors;
import com.ditty.invoke.action.Action;
import com.ditty.kit.LinkedKit;
import com.ditty.kit.StrKit;
import com.ditty.kit.ValueKit;

/**
 * @author dingnate
 *
 */
public class Routers {
	private static Routers ME = new Routers();

	Routers() {
	}

	public static Routers me() {
		return ME;
	}

	private Map<String, Action> actionMapping = new HashMap<String, Action>();

	public Routers add(Class<?>... controllerClasses) {
		//global
		AbstractActionIntercptor globalInterceptor = null;
		//controller
		for (Class<?> controllerClass : controllerClasses) {
			String controllerKey = getControllerKey(controllerClass);
			AbstractActionIntercptor controllerInterceptor = Interceptors.buildControllerInterceptor(controllerClass);
			if (!controllerClass.isAnnotationPresent(ClearActionInterceptor.class)) {
				globalInterceptor = Interceptors.me().getHead();
			}
			Method[] declaredMethods = controllerClass.getDeclaredMethods();
			for (Method method : declaredMethods) {
				if (!Modifier.isPublic(method.getModifiers()) || method.isAnnotationPresent(ClearAction.class)) {
					continue;
				}
				AbstractActionIntercptor actionInterceptor = Interceptors.buildActionInterceptor(method);
				//method
				if (!method.isAnnotationPresent(ClearActionInterceptor.class)) {
					actionInterceptor = LinkedKit.buildLinkedObjects(globalInterceptor, controllerInterceptor, actionInterceptor);
				}
				String actionKey;
				String[] argNames = null;
				ActionMapping annotation = method.getAnnotation(ActionMapping.class);
				if (annotation != null) {
					actionKey = ValueKit.getValue(annotation.actionKey(), method.getName());
					if (!actionKey.startsWith(ValueKit.STR_SLASH)) {
						actionKey = controllerKey + ValueKit.STR_SLASH + actionKey;
					}
					argNames = annotation.argNames();
					if (argNames.length != method.getParameterCount()) {
						throw new RuntimeException("argNames count in annotation[ActionMapping] is not equal to parameters count:" + method);
					}
				} else {
					actionKey = controllerKey + ValueKit.STR_SLASH + method.getName();
				}
				actionMapping.put(actionKey, new Action(actionInterceptor, method, controllerClass, argNames));
			}
		}
		return this;
	}

	/**
	 * @param controllerClass
	 * @return
	 */
	private String getControllerKey(Class<?> controllerClass) {
		String controllerKey = null;
		ActionMapping controllerAnn = controllerClass.getAnnotation(ActionMapping.class);
		if (controllerAnn != null) {
			controllerKey = controllerAnn.actionKey();
			if (!controllerKey.startsWith(ValueKit.STR_SLASH)) {
				controllerKey = ValueKit.STR_SLASH + controllerKey;
			}
		}
		return controllerKey;
	}

	public Action get(String target, String[] urlArgs) {
		Action action = actionMapping.get(target);
		int rIndex = 0;
		if (action == null && ((rIndex = StrKit.lastIndexOf(target, ValueKit.STR_SLASH)) != -1)) {
			action = actionMapping.get(target.substring(0, rIndex));
			urlArgs[0] = target.substring(rIndex + 1);
		}
		return action;
	}
}
